package cn.sunxyz.modules.memory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by yangrd on 2017/5/11.
 */
public final class DefaultNodeLinkInfoManger<V> implements NodeLinkInfoManger<V> {

    private Map<Key<V>, Collection<Date>> recordBook = new ConcurrentHashMap<>();

    private DefaultNodeLinkInfoManger() {

    }

    @Override
    public void addRecord(V value, V... friends) {
        if (null == friends) {
            return;
        }
        Date now = now();
        for (V friend : friends) {
            Key<V> key = buildKey(value, friend);
            Collection<Date> usageDate = recordBook.get(key);
            if (null == usageDate) {
                synchronized (this) {
                    if (null == usageDate) {
                        usageDate = new LinkedList<>();
                        recordBook.put(key, usageDate);
                    }
                }
            }
            usageDate.add(now);
        }
    }

    @Override
    public Collection<Date> getUseDate(V value, V friend) {
        return getUsageDate(value, friend);
    }

    @Override
    public Integer usageCount(V value, V friend) {
        return Optional.ofNullable(getUsageDate(value, friend)).map(usageDate -> usageDate == null ? 0 : usageDate.size()).get();
    }

    private Collection<Date> getUsageDate(V value, V friend) {
        Key<V> key = buildKey(value, friend);
        return recordBook.get(key);
    }

    private Date now() {
        return new Date();
    }

    private Key<V> buildKey(V value, V friend) {
        return new Key<V>(value, friend);
    }

    static class Key<V> {
        V value;
        V friend;

        public Key(V value, V friend) {
            this.value = value;
            this.friend = friend;
        }

        public void clear() {
            this.value = null;
            this.friend = null;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Key<?> key = (Key<?>) o;

            if (value != null ? !value.equals(key.value) : key.value != null) return false;
            return friend != null ? friend.equals(key.friend) : key.friend == null;
        }

        @Override
        public int hashCode() {
            int result = value != null ? value.hashCode() : 0;
            result = 31 * result + (friend != null ? friend.hashCode() : 0);
            return result;
        }
    }

    public static <V> DefaultNodeLinkInfoManger<V> getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private static class SingletonHolder {
        private static final DefaultNodeLinkInfoManger INSTANCE = new DefaultNodeLinkInfoManger();
    }
}
